# -*- coding: utf-8 -*-
#loading levels and stuff

import pygame
import os
import re
import sys
import glob
import random

import data
import character
import sound
import effects
import cannon
import default

#hårdkodar lite leveldata
level_width = 1000
level_height = 1000

level_dir = os.path.join('data','levels')

# Mapping from level-file-notation to tile-matrix indices
index_map = { ' ' : 0,  #empty, background 
              '#' : 1,  #street without border
              '-' : 2,  #north border
              '_' : 3,  #south
              '|' : 4,  #west
              '!' : 5,  #east

              '<' : 6,  #north,west
              '>' : 7,  #north, east
              '0' : 8,  #west, east
              'o' : 9,  #north, south
              'i' : 10, #north, west, east
              'U' : 11, #south, west, east
              'd' : 12, #south, west
              'b' : 13} #south, east
              

# Same as index_map, but defining which tile indices can be tread upon
walkable = { 0 : False,
             1 : True }

class Tile(pygame.sprite.Sprite):
    def __init__(self, rect, index):
        pygame.sprite.Sprite.__init__(self)
        self.image = None #We don't use this class to draw
        self.rect = pygame.rect.Rect(rect)
        self.index = index


class BasicLevel:
    def __init__(self, file):
        """Set up and load a tile based level"""

        # A level has the following layers;
        # far background (bbg_list)
        # near background (fbg_list)
        # characters (char_list)
        # tiles (level_map)
        # if we have time for it: foreground (fg_list)

        # self.initialize_level(file)
       
        files = glob.glob(os.path.join(data.tile_dir, "*.png"))
        #We want 0 first
        sorted = files[:] #same length

        #Nicest hack today
        for tile_file in files:
            #find the number
            number = int(re.findall(r"[0-9]+", tile_file)[0])
            #make it correct
            sorted[number] = tile_file
            
        #We load all of these files into memory
        #(which is more efficient than reloading
        #them each frame)
        self.all_tiles = []
        for img_file in sorted:
            image, rect = data.load_image(img_file, use_own_dir = True)
            self.all_tiles.append((image, rect))
        
        #self.bgimage, self.bgrect = data.load_image("tiles.png")

        self.bbg_list = []
        #self.parse_lvl(r"background:", self.bbg_list)

        #self.fbg_list = []
        #self.parse_lvl(r"2nd background:", self.fbg_list)

        #self.char_list = load_characters()

        #self.level_map = load_level()

        #self.fg_list = []
        #self.parse_lvl(r"foreground:", self.fg_list)
        
        #self.bggrid_size = (20, 20)
        #self.fggrid_size = (10, 10)
        
        #self.bggrid = [[]]
        #self.fggrid = [[]]

        self.tile_w = 80
        self.tile_h = 80
        
        #The parallaxing background needs to be smaller...but how much?
        self.bg_scale = 2
        #self.fg_scale = 1

        self.player_group = pygame.sprite.Group()
        self.tile_group = pygame.sprite.Group()  
        self.enemy_group = pygame.sprite.Group() #living enemies
        self.dying_group = pygame.sprite.Group() #things that want to finish their animations
        self.effects_group = pygame.sprite.Group() #gore and stuff represented by sprites
        self.cannon_group = pygame.sprite.Group()  #things that fire stuff, but do not hurt
        self.damaging_group = pygame.sprite.Group() #things that hurt (bullets)
        self.player_bullets = pygame.sprite.Group() 
        
        self.player_start = (100,100)
        
        #self.bgmusic = "robotsong.ogg"
        
        self.parse_lvlfile(file)        

        #We only store the tiles once, and reference them by a number
        #self.tilemap, self.tile_rect = data.load_image("tiles.png")
        #self.tilemap_dimensions = (self.tile_rect.width / self.tile_w,
        #                          self.tile_rect.height / self.tile_h)
        self.player = character.Player(os.path.join("robot", "standing"), self.player_start, self.bg_scale) 
        self.player_group.add(self.player)        

        sound.play_music(self.bgmusic)

        self.font = pygame.font.Font(default.font, 75)
        
        self.timerstart = pygame.time.get_ticks()
        self.curr_time = self.timerstart / 1000
        self.update_timer()



    def draw(self, camera, surface):
        """Draw the part of level that can be seen by camera,
        to surface"""
        self.draw_bg(camera, surface)
        #self.draw_fg(camera, surface)

    def get_tile(self, index):
        """Get the surface/rect of tile index"""
        
        return self.all_tiles[index - 1] #starting on 1

    #def get_tile_by_point(self, point):
    #    """Return the tile where point lies"""
    #    for tile in self.bbg_list:
    #        if tile.rect.collidepoint(point):
    #            return tile
            
    def draw_bg(self, camera, surface):
        """Draw the topmost layer of the parallaxing background"""
        
        to_draw = camera.collidelistall(self.bbg_list)

        for index in to_draw:
            tile = self.bbg_list[index]
            if tile.index is not 0:
                image, rect = self.get_tile(tile.index)
                topleft = (tile.rect.left - camera.left, tile.rect.top - camera.top)
                surface.blit(image, topleft)#, area


    def draw_fg(self, camera, surface):
        """Draw the bottom layer of the parallaxing background"""
        start_tile_x = (((camera[0] / self.fg_scale)
                         / self.tile_w)
                        % self.fggrid_size[0])
        start_tile_y = (((camera[1] / self.fg_scale)
                         / self.tile_h)
                        % self.fggrid_size[1])

        draw_pos = (0,0)

        for y in xrange(0, camera.height/self.tile_h):
            for x in xrange(0, camera.width/self.tile_w):
                area = self.get_tile(self.fggrid[x][y], self.fggrid_size)
                dest = (self.tile_w * x, self.tile_h * y)
                surface.blit(self.tilemap, dest, area)
      
    def parse_lvlfile(self, file): #wohoo, det funkish
        """parse a levelfile. Should probably be merged into __init__.
        Does not return anything, but instead, it saves the level in self.level_grid."""
        
        #The format is this:
        # """
        # width: x
        # height: y
        # level:
        # HUGE  MATRIX OF ASCII LETTERS
      
        fullpath = os.path.join(level_dir,file)
        lvl = open(fullpath, 'r')
        text = lvl.read() #jonneförhelveteinteöverlagradatamodulen!!!
        
        # -Hi, my name is Jonne and I...shortened your syntax
        # -Hi, Jonne!
        
        try:
            w = re.findall(r'width: [0-9]+', text)[0]
            w = re.findall(r'[0-9]+', w)[0]
            grid_w = int(w)
        except IndexError:
            print "Invalid file:", file, ". \n Must include a 'width: x'"

        try:
            h = re.findall(r'height: [0-9]+', text)[0]
            h = re.findall(r'[0-9]+', h)[0]
            grid_h = int(h)
        except IndexError:
            print "Invalid file:", file, ". \n Must include a 'height: x'"

        try:
            song = re.findall(r'music:.+', text)[0]
            song = song[len("music: "):]
            song = re.findall(r'.+\.ogg', song)[0]
            self.bgmusic = song
        except IndexError:
            self.bgmusic = "robotsong.ogg"
        
        try:
            time = re.findall(r'time: [0-9]+', text)[0]
            time = re.findall(r'[0-9]+', time)[0]
            self.maxtime = int(time)
        except IndexError:
            self.maxtime = 30
            
        match = re.search(r'level:',text)
        if match is not None:
            self.level_grid = []
            level_lines = text[match.start() + len("level:") + 1:].splitlines()
            
            linenr = 0
            for line in level_lines:
                row = []
                tilenr = 0           
                for tile in line:
                    try:
                        row.append(index_map[tile])
                        
                    except KeyError:
                        row.append(index_map[' '])
                        if tile == 'S' or tile == 's':
                            self.player_start = tilenr * self.tile_w, (linenr + 1) * self.tile_h
                        elif tile == 'H' or tile == 'h':
                            # +1 because we want to know where the bottomleft of the character should be
                            pos = (tilenr * self.tile_w, (linenr + 1) * self.tile_h)
                            tile = ' ' #a hack, but hopefully it works...
                            path = os.path.join("human", "walking")
                            anenemy = character.Enemy(path,
                                                      pos,
                                                      self.bg_scale,
                                                      2,
                                                      random.choice(('left', 'right')))
                            self.enemy_group.add(anenemy)
                        elif tile == "r" or tile == "R":
                            pos = (tilenr * self.tile_w, (linenr + 1)* self.tile_h)
                            self.cannon_group.add(cannon.Cannon(pos, "right"))
                        elif tile == "l" or tile == "L":
                            pos = (tilenr * self.tile_w, (linenr + 1)* self.tile_h)
                            self.cannon_group.add(cannon.Cannon(pos, "left"))
                        
                        else:
                            print "Undefined character", tile ,"in", file
                    tilenr += 1
                linenr += 1 

                self.level_grid.append(row)
        
        else:
            print "Invalid file:", file, ". \n Must include a 'level: x'"
            sys.exit(0)
        
        self.levelrect = pygame.Rect(0, 0, grid_w * self.tile_w, grid_h * self.tile_h)

        try:
            x = 0
            y = 0
            for row in self.level_grid:
                for index in row:
                    
                    pos = (x * self.tile_w, y * self.tile_h)
                    size = self.all_tiles[0][1].size #all tiles are of the same size
                    tile = Tile((pos, size), index)
                    self.bbg_list.append(tile)
                    if index is not 0:
                        self.tile_group.add(tile)

                    x += 1
                y += 1
                x = 0

        except IndexError:
            print "No tile files found! Cannot load level."
            sys.exit(0)

    def gore_splash(self, pos, many = 10):

        i = 0
        while i < many:
            vel = random.randint(-10,10), random.randint(-10,10)
            
            agore = effects.Gore(os.path.join("gore", "standard"), pos, vel, self.bg_scale)
            agore.accelerate(vel)
            self.effects_group.add(agore)
            i += 1
            
    def update_timer(self):
        """Updates, and draws? the Timer"""
        self.curr_time = self.maxtime - (pygame.time.get_ticks() - self.timerstart) / 1000
        
        self.timer_image = self.font.render(str(self.curr_time), 1, (255, 255, 255))
        
        return self.curr_time
        
        
